package com.example.demo.common.encrypt;

import org.apache.tomcat.util.codec.binary.Base64;

import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.interfaces.DSAPrivateKey;
import java.security.interfaces.DSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * DSA安全编码组件
 */
public class DSAEncrypt {

    public static final String ALGORITHM = "DSA";

    /**
     * 默认密钥字节数
     *
     * <pre>
     * DSA
     * Default Keysize 1024
     * Keysize must be a multiple of 64, ranging from 512 to 1024 (inclusive).
     * </pre>
     */
    private static final int KEY_SIZE = 1024;

    /**
     * 默认种子
     */
    private static final String DEFAULT_SEED = "0f22507a10bbddd07d8a3082122966e3";

    /**
     * 用私钥对信息生成数字签名
     *
     * @param content    加密数据
     * @param privateKey 私钥
     * @return
     * @throws Exception
     */
    public static String sign(String content, String privateKey) throws Exception {
        // KEY_ALGORITHM 指定的加密算法
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
        // 用私钥对信息生成数字签名
        Signature signature = Signature.getInstance(keyFactory.getAlgorithm());
        signature.initSign(privateKey(privateKey));
        signature.update(content.getBytes(StandardCharsets.UTF_8));
        return Base64.encodeBase64String(signature.sign());
    }

    /**
     * 校验数字签名
     *
     * @param content   加密数据
     * @param publicKey 公钥
     * @param sign      数字签名
     * @return 校验成功返回true 失败返回false
     * @throws Exception
     */
    public static boolean verify(String content, String publicKey, String sign) throws Exception {
        // ALGORITHM 指定的加密算法
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);

        Signature signature = Signature.getInstance(keyFactory.getAlgorithm());
        signature.initVerify(publicKey(publicKey));
        signature.update(content.getBytes(StandardCharsets.UTF_8));

        // 验证签名是否正常
        return signature.verify(Base64.decodeBase64(sign));
    }

    /**
     * 默认生成密钥
     *
     * @return 公钥和私钥的数组
     * @throws Exception
     */
    public static String[] genKeyPair() throws Exception {
        return genKeyPair(DEFAULT_SEED);
    }

    /**
     * 生成密钥
     *
     * @param seed 种子
     * @return 公钥和私钥的数组
     * @throws Exception
     */
    public static String[] genKeyPair(String seed) throws Exception {
        KeyPairGenerator keygen = KeyPairGenerator.getInstance(ALGORITHM);
        // 初始化随机产生器
        SecureRandom secureRandom = new SecureRandom();
        secureRandom.setSeed(seed.getBytes());
        keygen.initialize(KEY_SIZE, secureRandom);

        KeyPair keys = keygen.genKeyPair();

        DSAPublicKey publicKey = (DSAPublicKey) keys.getPublic();
        DSAPrivateKey privateKey = (DSAPrivateKey) keys.getPrivate();

        String publicKeyString = new String(Base64.encodeBase64(publicKey.getEncoded()));
        String privateKeyString = new String(Base64.encodeBase64(privateKey.getEncoded()));

        return new String[]{publicKeyString, privateKeyString};
    }

    /**
     * 将公钥文本转换为公钥对象
     * @param publicKey 公钥的文本
     * @return 公钥
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     */
    private static PublicKey publicKey(String publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
        //base64编码的公钥
        byte[] decoded = Base64.decodeBase64(publicKey);
        return KeyFactory.getInstance(ALGORITHM).generatePublic(new X509EncodedKeySpec(decoded));
    }

    /**
     * 将私钥文本转换为私钥对象
     * @param privateKey 私钥文本
     * @return 私钥
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     */
    private static PrivateKey privateKey(String privateKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
        byte[] decoded = Base64.decodeBase64(privateKey);
        return KeyFactory.getInstance(ALGORITHM).generatePrivate(new PKCS8EncodedKeySpec(decoded));
    }
}
